use crate::tokstr::TokStr;
pub struct Parser {
    stream: Box<TokStr>,
}

use crate::expr::Expr;
impl Parser {
    pub fn new(stream: TokStr) -> Self {
        Self {
            stream: Box::new(stream),
            // exprs: Vec::new(),
        }
    }
    pub fn parse_expr(&mut self) -> Option<Expr> {
        if let Some(Expr::Neg(_)) = self.stream.peek() {
            self.stream.next();
            let lhs = self.parse_primary().expect("Lack of first element");
            self.parse_additive(Some(Expr::Neg(Some(Box::new(lhs)))))
        } else {
            self.parse_additive(None)
        }
    }
    fn parse_primary(&mut self) -> Option<Expr> {
        // or fun call?
        if let Some(elem) = self.stream.peek() {
            // println!("peek {elem}");
            match elem {
                Expr::Cstf(_) | Expr::Csti(_) => {
                    self.stream.next();
                    Some(elem)
                }
                Expr::Var(_) => {
                    self.stream.next(); // eat the var
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        Some(elem)
                    }
                }
                Expr::Bra => {
                    self.stream.next(); // eat the bra
                    let res = self.parse_expr();
                    if let Some(Expr::Ket) = self.stream.peek() {
                        self.stream.next();
                        res
                    } else {
                        panic!("No Paired Parenthese");
                    }
                }
                Expr::ArcSin(_) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::ArcCos(_) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::ArcTan(_) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::Sin(_) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::Cos(_) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::Tan(_) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::Log(_, _) => {
                    self.stream.next();
                    if let Some(Expr::Bra) = self.stream.peek() {
                        self.parse_funcal(elem)
                    } else {
                        None
                    }
                }
                Expr::Pow(_, _) => {
                    panic!("^b could not be a clause")
                    //     self.stream.next();
                    //     if let Some(Expr::Bra) = self.stream.peek() {
                    //         self.parse_funcal(elem)
                    //     } else {
                    //         None
                    //     }
                }
                _ => {
                    println!("got {:?} at line 415", elem);
                    None
                } // comma could return None
            }
        } else {
            println!("None at line {}", line!());
            None
        }
    }

    fn parse_power(&mut self) -> Option<Expr> {
        let base = self.parse_primary().expect("Not a variable or constant");
        if let Some(Expr::Pow(_, _)) = self.stream.peek() {
            self.stream.next(); //eat the power sign
            let po = self.parse_primary();
            Some(Expr::Pow(
                Some(Box::new(base)),
                po.map(Box::new),
                //     if let Some(inner_po) = po {
                //         Some(Box::new(inner_po))
                //     } else {
                //         None
                //     },
            ))
        } else {
            Some(base)
        }
    }
    fn parse_factorial(&mut self) -> Option<Expr> {
        self.parse_power()
    }
    fn parse_multiplicative(&mut self) -> Option<Expr> {
        let mut lhs = self.parse_factorial();
        while let Some(e) = self.stream.peek() {
            match e {
                Expr::Mul(_, _) => {
                    self.stream.next();
                    let rhs = self.parse_factorial();
                    lhs = Some(Expr::Mul(
                        if let Some(inner_lhs) = lhs {
                            Some(Box::new(inner_lhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                        if let Some(inner_rhs) = rhs {
                            Some(Box::new(inner_rhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                    ));
                }
                Expr::Div(_, _) => {
                    self.stream.next();
                    let rhs = self.parse_factorial();
                    lhs = Some(Expr::Div(
                        if let Some(inner_lhs) = lhs {
                            Some(Box::new(inner_lhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                        if let Some(inner_rhs) = rhs {
                            Some(Box::new(inner_rhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                    ));
                }
                _ => break,
            }
        }
        lhs
    }
    fn parse_additive(&mut self, lhs: Option<Expr>) -> Option<Expr> {
        let mut lhs = if lhs.is_none() {
            self.parse_multiplicative()
        } else {
            lhs
        };
        // println!("parse multiplicative {:?}", lhs.clone());
        while let Some(e) = self.stream.peek() {
            match e {
                Expr::Add(_, _) => {
                    self.stream.next();
                    let rhs = self.parse_multiplicative();
                    // println!("parse multiplicative {:?}", rhs.clone());
                    lhs = Some(Expr::Add(
                        if let Some(inner_lhs) = lhs {
                            Some(Box::new(inner_lhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                        if let Some(inner_rhs) = rhs {
                            Some(Box::new(inner_rhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                    ));
                }
                Expr::Sub(_, _) => {
                    self.stream.next();
                    let rhs = self.parse_multiplicative();
                    // println!("parse multiplicative {:?}", rhs.clone());
                    lhs = Some(Expr::Sub(
                        if let Some(inner_lhs) = lhs {
                            Some(Box::new(inner_lhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                        if let Some(inner_rhs) = rhs {
                            Some(Box::new(inner_rhs))
                        } else {
                            Some(Box::new(Expr::Var("Nil".to_string())))
                        },
                    ));
                }
                _ => break, // comma could break the loop
            }
        }
        lhs
    }
    fn parse_funcal(&mut self, fun_name: Expr) -> Option<Expr> {
        let k = self.stream.next(); // eat bra
                                    // println!("first in the parse_funcal: {k:?}");
        let mut v: Vec<Expr> = Vec::new();
        while let Some(p) = self.parse_expr() {
            v.push(p);
            match self.stream.next() {
                Some(Expr::Comma) => (), // println!("eat a comma"),
                Some(Expr::Ket) => {
                    // println!("eat ket");
                    break;
                }
                x => {
                    panic!("Expect Comma seperated parameter list surrounded by (), however {x:?}")
                }
            }
        }
        match fun_name {
            Expr::Sin(_) => {
                if v.len() == 1 {
                    Some(Expr::Sin(Some(Box::new(v[0].clone()))))
                } else {
                    panic!("Sin accept just one parameter")
                }
            }
            Expr::Cos(_) => {
                if v.len() == 1 {
                    Some(Expr::Cos(Some(Box::new(v[0].clone()))))
                } else {
                    panic!("Sin accept just one parameter")
                }
            }
            Expr::Tan(_) => {
                if v.len() == 1 {
                    Some(Expr::Tan(Some(Box::new(v[0].clone()))))
                } else {
                    panic!("Tan accept just one parameter")
                }
            }
            Expr::ArcSin(_) => {
                if v.len() == 1 {
                    Some(Expr::ArcSin(Some(Box::new(v[0].clone()))))
                } else {
                    panic!("Sin accept just one parameter")
                }
            }
            Expr::ArcCos(_) => {
                if v.len() == 1 {
                    Some(Expr::ArcCos(Some(Box::new(v[0].clone()))))
                } else {
                    panic!("Sin accept just one parameter")
                }
            }
            Expr::ArcTan(_) => {
                if v.len() == 1 {
                    Some(Expr::ArcTan(Some(Box::new(v[0].clone()))))
                } else {
                    panic!("Tan accept just one parameter")
                }
            }
            Expr::Log(_, _) => {
                if v.len() == 2 {
                    Some(Expr::Log(
                        Some(Box::new(v[0].clone())),
                        Some(Box::new(v[1].clone())),
                    ))
                } else {
                    panic!("Sin accept two parameter")
                }
            }
            _ => panic!("No supported function"),
        }
    }
}
